<?php
namespace StarCloud\Library\Sdk;
use Phalcon\Di;
/**
 *
 * Class Demo
 * 文档地址: https://docs.qq.com/doc/DT1d6bEN0dFBITHJZ
 */
class HenanPay
{

    public $service_url;
    public $publicKey;
    public $privateKey;
    public $tenantCode;
    public $merId;     //商户号
    public $levyCode;  //税优地编码
    public $bankCode;  //银行通道编码
    public $desKey = '35CB449250324157BA5BC4EFE71B68B7';

    private $rsa = [
        'pri' => '-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgEzgAW7zxNGpPMz/M5YInnL+yPFhELMZ8AvxsvkVyLIX65tuU1dT
km0WmUSLrh0+7e/AbGTUQtyz8CPu7ng1RkHiW2gLZ3J5DcV0C0384uopE7MA1q7s
2gKjKyNzCgQLpSYXqeRALANP+ZNF9cy4pvM5RKebB6NWryD6hNdwZAePAgMBAAEC
gYAixIzhaU5ypF/jNuhVysAesiyfPo8W8XwnasDO9pM2OKtOOK9op1tqCvZ2kdXF
VFi4PgbH81fqCVdqaP1hUHbdhlpOLILwIN58wP9ETicY15z60+tqD5Admi81YW+V
rUSfmMhjlp7LGnIvRXY7FsQ60+NUIC7fccFSocIY5xhfgQJBAJAFqRPHfghnVreB
FWYCLTLXHSKQgf2rF1EvTPvlhcLbHmsKGFkD7E1c1QttoroBFD1sztYRKFtj28Wi
RlVPA6kCQQCIpU4k33ugrwVerE7/qrbBHuwXkdpWzuaIY8L5jXUfLHMSVVexPcVl
uBcWwwdnVX+zGeb5CQBUxDge8Ni/czR3AkATh6D43Kl7jD/XHHsBXTQx27fIsx3d
fzDnQmnHEsXDuaDzVOgeUgjeKMN/DDvvyyuqdLHLl4IIeo8XyryM3u0ZAkBZzcIo
q5N1S/FMghO9JTXMgAULjHihOoL5ug7GsXf6z9ykfOAQBRe5PR43gF9aQy+Uxn4s
xwSnsPltJD5evFkLAkEAj3X6XD5pVP95E0KGvLRDLIBcBuD2aZEfCTUB+a/aHTHu
SBburKi6ukKDp23G/dQM6+oRGqiRMRH5sNDvBFxYvw==
-----END RSA PRIVATE KEY-----',
        'pub' => '-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgEzgAW7zxNGpPMz/M5YInnL+yPFhELMZ8AvxsvkVyLIX65tuU1dTkm0WmUSLrh0+7e/AbGTUQtyz8CPu7ng1RkHiW2gLZ3J5DcV0C0384uopE7MA1q7s2gKjKyNzCgQLpSYXqeRALANP+ZNF9cy4pvM5RKebB6NWryD6hNdwZAePAgMBAAE=
-----END PUBLIC KEY-----'
    ];

    public function __construct()
    {
        $this->service_url = 'http://spay.hui7z.com/';
        $this->publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbfWSbWP0tXtPSxgXX4kcdG5G8hPFdrTMEu4xVDDJYRAQ8W2wHl6Ts1Q+JYXaVbvgEqbqrRY6ezWL2TJiA7iobb8dFI53ED+eSVHJg1Sc5HO/P/n9tlMWpR+t2QsuB9BRc6k7u9M9w9yeIZ0meq/jjjVt1Ut9ZV/hpifO+BVeO0QIDAQAB';
//        $this->publicKey = 'MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgEzgAW7zxNGpPMz/M5YInnL+yPFhELMZ8AvxsvkVyLIX65tuU1dTkm0WmUSLrh0+7e/AbGTUQtyz8CPu7ng1RkHiW2gLZ3J5DcV0C0384uopE7MA1q7s2gKjKyNzCgQLpSYXqeRALANP+ZNF9cy4pvM5RKebB6NWryD6hNdwZAePAgMBAAE=';
        $this->privateKey = 'MIICWwIBAAKBgEzgAW7zxNGpPMz/M5YInnL+yPFhELMZ8AvxsvkVyLIX65tuU1dTkm0WmUSLrh0+7e/AbGTUQtyz8CPu7ng1RkHiW2gLZ3J5DcV0C0384uopE7MA1q7s2gKjKyNzCgQLpSYXqeRALANP+ZNF9cy4pvM5RKebB6NWryD6hNdwZAePAgMBAAECgYAixIzhaU5ypF/jNuhVysAesiyfPo8W8XwnasDO9pM2OKtOOK9op1tqCvZ2kdXFVFi4PgbH81fqCVdqaP1hUHbdhlpOLILwIN58wP9ETicY15z60+tqD5Admi81YW+VrUSfmMhjlp7LGnIvRXY7FsQ60+NUIC7fccFSocIY5xhfgQJBAJAFqRPHfghnVreBFWYCLTLXHSKQgf2rF1EvTPvlhcLbHmsKGFkD7E1c1QttoroBFD1sztYRKFtj28WiRlVPA6kCQQCIpU4k33ugrwVerE7/qrbBHuwXkdpWzuaIY8L5jXUfLHMSVVexPcVluBcWwwdnVX+zGeb5CQBUxDge8Ni/czR3AkATh6D43Kl7jD/XHHsBXTQx27fIsx3dfzDnQmnHEsXDuaDzVOgeUgjeKMN/DDvvyyuqdLHLl4IIeo8XyryM3u0ZAkBZzcIoq5N1S/FMghO9JTXMgAULjHihOoL5ug7GsXf6z9ykfOAQBRe5PR43gF9aQy+Uxn4sxwSnsPltJD5evFkLAkEAj3X6XD5pVP95E0KGvLRDLIBcBuD2aZEfCTUB+a/aHTHuSBburKi6ukKDp23G/dQM6+oRGqiRMRH5sNDvBFxYvw==';
        $this->tenantCode = 'ccthrcloud';
        $this->merId = '6000011742';
        $this->levyCode = '1000256241';
        $this->bankCode = '6000341341';
    }

    public function querySign($name, $idCard, $bankCard, $mobile)
    {
        $method = 'soho/querySoho/' . $this->tenantCode;

        $request_body = [
            'name' => $this->encrypt($name, $this->desKey),
            'cardNo' => $this->encrypt($bankCard, $this->desKey),
            'idCard' => $this->encrypt($idCard, $this->desKey),
            'mobile' => $this->encrypt($mobile, $this->desKey),
            'levyCode' => $this->levyCode,
        ];

        $result = $this->_public_request($request_body, $method);

        if (isset($result['resCode']) && $result['resCode'] == '0000' && $result['state'] == 'SIGN') {
            return true;
        }

        return false;
    }

    public function queryOrder($orderNo, $payItemId)
    {
        $method = 'payment/queryBatch/' . $this->tenantCode;
        $payItems = [];
        $payItems[] = [
            'payItemId' => $payItemId,
            'merOrderId' => $orderNo,
        ];

        $request_body = [
            'merBatchId' => $orderNo, //批次号
            'queryItems' => base64_encode(json_encode($payItems, JSON_UNESCAPED_UNICODE)),
        ];
        $result = $this->_public_request($request_body, $method);

        if (isset($result['resCode']) && $result['resCode'] == '0000') {
            $data = json_decode(base64_decode($result['data']), true);
            if (is_array($data)) {
                return $data[0];
            }
            return false;
        }

        return false;
    }

    public function sign($name, $idCard, $bankCard, $mobile)
    {
        $method = 'soho/singleSoho/' . $this->tenantCode;

        $request_body = [
            'name' => $this->encrypt($name, $this->desKey),
            'cardNo' => $this->encrypt($bankCard, $this->desKey),
            'idCard' => $this->encrypt($idCard, $this->desKey),
            'mobile' => $this->encrypt($mobile, $this->desKey),
            'levyCode' => $this->levyCode,
            'idCardType' => 'A'
        ];

        return $this->_public_request($request_body, $method);
    }
    /*
    * 付款交易接口
    */
    public function pay($orderNo, $amount, $name, $bankCard, $idCard, $mobile)
    {
        $method = 'payment/pay/' . $this->tenantCode;
        $payItems = [];
        $payItems[] = [
            'merOrderId' => $orderNo, // 订单号
            'amt' => $amount, // 金额
            'payeeName' => $name, // 收款人名称
            'payeeAcc' => $bankCard, // 收款人账号
            'idCard' => $idCard, // 身份证号
            'mobile' => $mobile, // 手机号
            'inType' => 'API',
            'paymentType' => 'CARD',
            'accType' => 'PRI',
            'levyCode' => $this->levyCode,
            'bankCode' => $this->bankCode,
        ];
        $request_body = [
            'totalCount' => 1,//付款总笔数
            'totalAmt' => $amount, //付款总金额
            'merBatchId' => $orderNo, //批次号
            'payItems' => base64_encode(json_encode($payItems, JSON_UNESCAPED_UNICODE)),
        ];

        return $this->_public_request($request_body, $method);
    }


    /**
     * 功能：通用请求
     * @param $request_body
     * @param $method
     * @param string $signType
     * @param string $encType
     * @return array|false|mixed
     * Author：Liug 2021/12/10
     */
    public function _public_request($request_body, $method, $signType = 'RSA', $encType = 'DES')
    {
        $api_url = $this->service_url . $method;
        $com = [
            'version' => 1,
            'reqId' => md5(uniqid()),
            'signType' => $signType,
            'encType' => $encType,
            'merId' => $this->merId
        ];
        $request = array_merge($com, $request_body);
        $sign = $this->makeSign($request, 'sign');
        $request['sign'] = $this->genSign($sign, $this->privateKey);
        $request_json = json_encode($request);
        Di::getDefault()->get("logger")->info("henan_pay request " . $request_json);
        $result = $this->sendHttpRequest($request_json, $api_url);
        Di::getDefault()->get("logger")->info("henan_pay response " . $result);
        $result = json_decode($result, true);
        return !is_array($result) || empty($result) ? false : $result;
    }


    //**********************************************工具类***************************************************

    public function makeSign($body, $type)
    {
        ksort($body, SORT_NATURAL | SORT_FLAG_CASE);//排序不区分大小写
        $buff = "";
        foreach ($body as $k => $v) {
            //签名
            if ($type == 'sign') {
                if ($k == 'signType' || $k == 'encType' || $k == 'sign' || $v === '' || is_array($v)) {
                    continue;
                }
            }

            //验签
            if ($type == 'verify') {
                if ($k == 'resCode' || $k == 'resMsg' || $k == 'ip' || $k == 'sign' || $v === '' || is_array($v)) {
                    continue;
                }
            }

            $buff .= $k . "=" . $v . "&";
        }
        return trim($buff, "&");
    }

    /**
     * 生成 sign 签名
     * @param string $toSign 数据
     * @param string $privateKey 私钥
     * @return string
     */
    public function genSign($toSign, $privateKey)
    {
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($privateKey, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";

        $key = openssl_get_privatekey($privateKey);
        openssl_sign($toSign, $signature, $key);
        openssl_free_key($key);
        $sign = base64_encode($signature);
        return $sign;
    }

    /**
     * 功能：校验 sign 签名
     * @param $pubKey 公钥
     * @param $sign  请求获取到 sign 值
     * @param $toSign 自己拼接到的字符串
     * @return bool
     * Author：Liug 2021/12/10
     */
    function checkSign($pubKey, $sign, $toSign)
    {
        $pem = chunk_split(trim($pubKey), 64, "\n");
        $pubKey = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----";
        $publicKeyId = openssl_pkey_get_public($pubKey);
        $result = openssl_verify($toSign, base64_decode($sign), $publicKeyId, OPENSSL_ALGO_SHA1);
        openssl_free_key($publicKeyId);
        return $result === 1 ? true : false;
    }

    /**
     * 私钥加密
     * @param $data
     * @param $private_key
     * @return string
     */
    public function privateEncrypt($data, $private_key)
    {
        if (is_array($data)) {
            ksort($data);
            $data = json_encode($data);
        }
        $pem = chunk_split(trim($private_key), 64, PHP_EOL);
        $pem = "-----BEGIN RSA PRIVATE KEY-----" . PHP_EOL . $pem . "-----END RSA PRIVATE KEY-----";
        $privateKey = openssl_pkey_get_private($pem);
        $ciphertext = '';
        $data = str_split($data, 117); // 加密的数据长度限制为比密钥长度少11位，如128位的密钥最多加密的数据长度为117
        foreach ($data as $d) {
            openssl_private_encrypt($d, $crypted, $privateKey); // OPENSSL_PKCS1_PADDING
            $ciphertext .= $crypted;
        }
        return base64_encode($ciphertext);
    }

    /**
     * 私钥解密
     * @param $data
     * @param $private_key
     * @param bool $unserialize
     * @return mixed
     * @throws \Exception
     */
    public function privateDecrypt($data, $private_key)
    {
        $pem = chunk_split(trim($private_key), 64, "\n");
        $pem = "-----BEGIN RSA PRIVATE KEY-----\n" . $pem . "-----END RSA PRIVATE KEY-----";
        $privateKey = openssl_pkey_get_private($pem);
        $crypto = '';
        foreach (str_split(base64_decode($data), 128) as $chunk) {
            openssl_private_decrypt($chunk, $decryptData, $privateKey);
            $crypto .= $decryptData;
        }
        if ($crypto === false) {
            throw new \Exception('Could not decrypt the data.');
        }
        return json_decode($crypto, true);
    }


    /**
     * 公钥加密
     * @param $data
     * @param $public_key
     * @param bool $serialize 是为了不管你传的是字符串还是数组，都能转成字符串
     * @return string
     * @throws \Exception
     */
    public function publicEncrypt($data, $public_key)
    {
        $pem = chunk_split(trim($public_key), 64, "\n");
        $pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----";
        $publicKey = openssl_pkey_get_public($pem);
        $ciphertext = '';
        if (is_array($data)) {
            ksort($data);
            $data = json_encode($data);
        }
        // 加密的数据长度限制为比密钥长度少11位，如128位的密钥最多加密的数据长度为117
        $data = str_split($data, 117);
        foreach ($data as $d) {
            openssl_public_encrypt($d, $crypted, $publicKey); // OPENSSL_PKCS1_PADDING
            $ciphertext .= $crypted;
        }
        if ($ciphertext === false) {
            throw new \Exception('Could not encrypt the data.');
        }
        openssl_free_key($publicKey);
        return base64_encode($ciphertext);
    }


    /**
     * 公钥解密
     * @param $data
     * @param $public_key
     * @return mixed
     * @throws \Exception
     */
    public function publicDecrypt($data, $public_key)
    {
        $pem = chunk_split(trim($public_key), 64, PHP_EOL);
        $pem = "-----BEGIN PUBLIC KEY-----" . PHP_EOL . $pem . "-----END PUBLIC KEY-----";
        $pem = openssl_pkey_get_public($pem);
        $dataArray = str_split(base64_decode($data), 128);
        $decrypted = '';
        foreach ($dataArray as $subData) {
            $subDecrypted = null;
            openssl_public_decrypt($subData, $subDecrypted, $pem);
            $decrypted .= $subDecrypted;
        }
        return $decrypted;
    }


    public function encrypt($data, $key)
    {
        if (is_array($data)) {
            ksort($data);
            $data = json_encode($data);
        }
        $data = self::pkcs5Pad($data, 8);
        $sign = openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
        $sign = base64_encode($sign);
        return $sign;
    }

    //des解密（ECB模式）
    public function decrypt($data, $key)
    {
        $sign = openssl_decrypt(base64_decode($data), 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
        $sign = self::pkcs5Unpad($sign);
        return $sign;
    }

    public function hex2bin($hexData)
    {
        $binData = "";
        for ($i = 0; $i < strlen($hexData); $i += 2) {
            $binData .= chr(hexdec(substr($hexData, $i, 2)));
        }
        return $binData;
    }

    public function pkcs5Pad($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    public function pkcs5Unpad($text)
    {
        $pad = ord($text[strlen($text) - 1]);
        if ($pad > strlen($text))
            return false;
        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
            return false;
        }
        return substr($text, 0, -1 * $pad);
    }


    /*
     * **********************   数据请求  **********************
     */
    private function sendHttpRequest($data, $url)
    {
        $opts = $data;
        if (is_array($data)) {
            $opts = json_encode($data);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不验证证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不验证HOST
        curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 链接超时
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type:application/json;charset=UTF-8'));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $opts);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // 运行cURL，请求网页
        $html = curl_exec($ch);
        curl_close($ch);
        return $html;

    }

}

///**
// * 功能：付款交易接口
// * Author：Liug 2021/12/10
// */
//function pay()
//{
//    $demo = new Demo();
//    $param = [
//        'totalCount' => '1',
//        'totalAmt' => '0.01',
//        'batchNo' => time(),
//        'list' => [
//            [
//                'orderNumber' => time(), // 订单号
//                'amt' => '0.01', // 金额
//                'payeeName' => '马力', // 收款人名称
//                'payeeAcc' => '6217000010073232244', // 收款人账号
//                'idCard' => '150303195208072064', // 身份证号
//                'mobile' => '18614078822', // 手机号
//                'inType' => 'API',
//            ]
//        ]
//    ];
//
//    $rs_data = $demo->pay($param);
//    if ($rs_data === false) {
//        die('支付错误');
//    }
//    $request_sign = $rs_data['sign'];
//    $my_sign_str = $demo->makeSign($rs_data, 'verify');
//    $is_sign = $demo->checkSign($demo->publicKey, $request_sign, $my_sign_str);
//    if ($is_sign !== true) {
//        die('sign值校验失败');
//    }
//    $encrypt_data = base64_decode($rs_data['data']); //data 里数据解密后结果
//    var_dump($rs_data, $encrypt_data);
//
//}



